package com.jse.dao;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.nutz.dao.Chain;
import org.nutz.dao.Condition;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.impl.NutDao;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;

import com.jse.cache.Cache;
import com.jse.util.JseMap;
import com.jse.util.Strings;

public class Dao extends NutDao {

	private Cache cache;

	public Cache getCache() {
		return cache;
	}
	public void setCache(Cache cache) {
		this.cache = cache;
	}
	public Dao(DataSource dataSource) {
		super(dataSource);
	}
	
	@SuppressWarnings("unchecked")
	public List<Record> query(String tableName){
		List<Record> list=null;
		if(cache.containsKey("sqllist:"+tableName)) {
			list=(List<Record>) cache.get("sqllist:"+tableName);
		}else {
			list=super.query(tableName, null);
			cache.put("sqllist:"+tableName, list);
		}
		return list;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Record> query(String tableName,Condition cnd){
		List<Record> list=null;
		if(cnd==null) {
			if(cache.containsKey("sqllist:"+tableName)) {
				list=(List<Record>) cache.get("sqllist:"+tableName);
			}else {
				list=super.query(tableName, null);
				cache.put("sqllist:"+tableName, list);
			}
			return list;
		}else {
			return super.query(tableName, cnd);
		}
	}
	
	public int update(String tableName,JseMap chain,Condition cnd) {
		return super.update(tableName, Chain.from(chain), cnd);
	}
	public JseMap pager(String tableName,Condition cnd,int pageNumber,int pageSize) {
		Pager pager=new Pager(pageNumber, pageSize);
		List<Record> list=query(tableName, cnd, pager);
		JseMap mapper=new JseMap();
		mapper.put("list", list);
		int count=count(tableName,cnd);
		pager.setRecordCount(count);
		mapper.put("pager",pager);
		return mapper;
	}
	public JseMap pager(String tableName,Condition cnd,Pager pager) {
		List<Record> list=query(tableName, cnd, pager);
		JseMap mapper=new JseMap();
		mapper.put("list", list);
		int count=count(tableName,cnd);
		pager.setRecordCount(count);
		mapper.put("pager",pager);
		return mapper;
	}
	public Record fetch(String tableName,Condition cnd) {
		return super.fetch(tableName, cnd);
	}
	public int count(String tableName,Object cnd) {
		if(cnd instanceof Condition) {
			return super.count(tableName, (Condition) cnd);
		}else if(cnd instanceof String) {
				return super.count(tableName,Cnd.wrap(cnd.toString()));
		}else if(cnd==null) {
			return super.count(tableName, null);
		}else {
			return super.count(tableName, null);
		}
	}
	public List<Record> sql(String sq) {
		Sql sql = Sqls.create(sq);
	    sql.setCallback(new SqlCallback() {
	        public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
	            List<Record> list = new LinkedList<Record>();
	            while (rs.next())
	            	list.add(Record.create(rs));
	            return list;
	        }
	    });
	    execute(sql);
	    return sql.getList(Record.class);
	}
	public Object sql(String sq,String type) {
		Sql sql = Sqls.create(sq);
	    sql.setCallback(new SqlCallback() {
	        public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
	        	if(type.equals("map")) {
	        		Record map = null;
		            while (rs.next())
		            	map=Record.create(rs);
		            return map;
	        	}else if(type.equals("liststring")) {
	        		List<String> list = new LinkedList<String>();
		            while (rs.next())
		            	list.add(rs.getString(1));
		            return list;
	        	}else if(type.equals("str")||type.equals("string")) {
	        		String str="";
		            while (rs.next())
		            	str=rs.getString(1);
		            return str;
	        	}else if(type.equals("bool")||type.equals("boolean")) {
	        		Boolean bool=false;
		            while (rs.next())
		            	bool=rs.getBoolean(1);
		            return bool;
	        	}else {
	        		List<Record> list = new LinkedList<Record>();
		            while (rs.next())
		            	list.add(Record.create(rs));
		            return list;
	        	}
	        }
	    });
	    execute(sql);
	    return sql.getResult();
	}
	public Record fetch(String sql){
		Sql sq=Sqls.create(sql);
		sq.setCallback((conn,rs,sq1)->{
	    	            Record r = new Record();
	    	            while (rs.next())
	    	            	r=Record.create(rs);
	    	            return r;
	    	    }
			);
		execute(sq);
		return sq.getObject(Record.class);
	}
	public Record fetch(String sql,Object...param){
		Sql sq=Sqls.create(String.format(sql.replace("?", "%s"), param));
		sq.setCallback((conn,rs,sq1)->{
	    	            Record r = new Record();
	    	            while (rs.next())
	    	            	r=Record.create(rs);
	    	            return r;
	    	    }
			);
		execute(sq);
		return sq.getObject(Record.class);
	}

	public List<Record> select(String sql){
		return sql(sql);
	}
	public List<Record> select(String sql,Object...param) {
		Sql sq=Sqls.create(String.format(sql.replace("?", "%s"), param));
		sq.setCallback((conn,rs,sq1)->{
	    	            List<Record> list = new LinkedList<Record>();
	    	            while (rs.next())
	    	            	list.add(Record.create(rs));
	    	            return list;
	    	    }
			);
		execute(sq);
		return sq.getList(Record.class);
	}
	
	@SuppressWarnings("unchecked")
	public int delete(String table,Object cnd){
		StringBuffer sql = new StringBuffer("delete from ").append(table);
		if(!Strings.isEmpty(cnd)) {
			if(cnd instanceof Condition)
				sql.append(cnd);
			else if(cnd instanceof String) {
				String str=cnd.toString();
				sql.append(Cnd.wrap(str));
			}
			else if(cnd instanceof Integer) {
				sql.append(Cnd.where("id", "=", cnd));
			}else if(cnd.getClass().isArray()) {
				sql.append(Cnd.where("id", "in", cnd));
			}else if(cnd instanceof List) {
				sql.append(Cnd.where("id", "in", cnd));
			}else if(cnd instanceof Map) {
				Map<String, Object> mp=(Map<String, Object>) cnd;
				Cnd cn=Cnd.where("1", "=", 1);
				mp.forEach((k,v)->{
					sql.append(cn.and(k,"=",v));
				});
			}else {
				return -1;
			}
			return execute(Sqls.create(sql.toString())).getUpdateCount();
		}else {
			return -1;
		}
	}
}
